/**
 *
 * @author Anastasiya
 *
 */

#include "texwriter.h"
#include "util.h"
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <cstring>
#include <cstdlib>

using namespace std;



const string  TexWriter::HEADER_COLUMN_FORMAT = "|c|";
const string  TexWriter::EMPTY_ROW_HEADER_COLUMN_FORMAT = "l|";
const string  TexWriter::ROW_HEADER_COLUMN_FORMAT = "|l|";

const string  TexWriter::TABLE_HEADER_LINE = "\\cline{2-5}";
const string  TexWriter::TABLE_BODY_LINE = "\\hline";
const string  TexWriter::HEADER_MULTICOLUMN = "\\multicolumn{2}{" + HEADER_COLUMN_FORMAT + "}";
const string  TexWriter::ROW_HEADER_MULTICOLUMN = "\\multicolumn{1}{" + ROW_HEADER_COLUMN_FORMAT + "}";
const string  TexWriter::EMPTY_ROW_HEADER_MULTICOLUMN = "\\multicolumn{1}{" + EMPTY_ROW_HEADER_COLUMN_FORMAT + "}";

const string  TexWriter::TIME_SUBHEADER_NAME = "Execution time";
const string  TexWriter::VERTICES_SUBHEADER_NAME = "Removed edges";

const string  TexWriter::LATEX_COLUMN_DELIMITER = " & ";
const string  TexWriter::LATEX_NEWLINE = " \\\\ ";

const string  TexWriter::COLORED_TEXT_BEST_TIME = "\\textcolor{Red}";
const string  TexWriter::COLORED_TEXT_BEST_APPROACH = "\\textcolor{Blue}";

const string  TexWriter::LATEX_BEGIN_DOCUMENT = "\\begin{document}";
const string  TexWriter::LATEX_END_DOCUMENT = "\\end{document}";
const string  TexWriter::LATEX_BEGIN_TABLE = "\\begin{longtable}{ l  c | c | c | c |}";
const string  TexWriter::LATEX_END_TABLE = "\\end{longtable}";

const string  TexWriter::LATEX_DOCUMENT_CLASS = "\\documentclass[12pt]{book}";
const string  TexWriter::LATEX_USE_PACKAGE_FONT = "\\usepackage[T2A]{fontenc}";
const string  TexWriter::LATEX_USE_PACKAGE_ENCODING = "\\usepackage[cp1251]{inputenc}";
const string  TexWriter::LATEX_USE_PACKAGE_BABEL = "\\usepackage[english,russian]{babel}";
const string  TexWriter::LATEX_USE_PACKAGE_MULTIROW = "\\usepackage{multirow}";
const string  TexWriter::LATEX_USE_PACKAGE_LONGTABLE = "\\usepackage{longtable}";
const string  TexWriter::LATEX_USE_PACKAGE_COLOR = "\\usepackage[usenames,dvipsnames]{color}";

const string  TexWriter::RIGHT_BRACKET = "}";
const string  TexWriter::LEFT_BRACKET = "{";

const string  TexWriter::NEW_LINE = "\n";


const string TexResultRepresentation::RESULT_NO_TIME = "-";
const string TexResultRepresentation::RESULT_NO_EDGES = "-";
const string TexResultRepresentation::RESULT_FAILED = "FAILED";



TexWriter::TexWriter(string algorithmName1, string algorithmName2){
	tableHeader = TABLE_HEADER_LINE;
	tableHeader += NEW_LINE;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += HEADER_MULTICOLUMN;
	tableHeader += LEFT_BRACKET;
	tableHeader += algorithmName1;
	tableHeader += RIGHT_BRACKET;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += HEADER_MULTICOLUMN;
	tableHeader += LEFT_BRACKET;
	tableHeader += algorithmName2;
	tableHeader += RIGHT_BRACKET;
	tableHeader += LATEX_NEWLINE;
	tableHeader += TABLE_HEADER_LINE;
	tableHeader += NEW_LINE;

	tableHeader += EMPTY_ROW_HEADER_MULTICOLUMN;
	tableHeader += LEFT_BRACKET;
	tableHeader += RIGHT_BRACKET;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += TIME_SUBHEADER_NAME;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += VERTICES_SUBHEADER_NAME;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += TIME_SUBHEADER_NAME;
	tableHeader += LATEX_COLUMN_DELIMITER;
	tableHeader += VERTICES_SUBHEADER_NAME;
	tableHeader += LATEX_NEWLINE;
	tableHeader += TABLE_BODY_LINE;
	tableHeader += NEW_LINE;

	tableContent = "";

	texWriterInstanceCount++;
}

TexWriter::~TexWriter(){
	texWriterInstanceCount--;
}

void TexWriter::addResult(string graphName, TestResult* result1, TestResult* result2){


	TexResultRepresentation* resultRepresentation1 = new TexResultRepresentation(result1);
	TexResultRepresentation* resultRepresentation2 = new TexResultRepresentation(result2);

	tableContent += ROW_HEADER_MULTICOLUMN;
	tableContent += LEFT_BRACKET;
	tableContent += graphName;
	tableContent += RIGHT_BRACKET;
	tableContent += LATEX_COLUMN_DELIMITER;
	tableContent += resultRepresentation1->getTime();
	tableContent += LATEX_COLUMN_DELIMITER;
	tableContent += resultRepresentation1->getEdgesCount();
	tableContent += LATEX_COLUMN_DELIMITER;
	tableContent += resultRepresentation2->getTime();
	tableContent += LATEX_COLUMN_DELIMITER;
	tableContent += resultRepresentation2->getEdgesCount();
	tableContent += LATEX_NEWLINE;
	tableContent += TABLE_BODY_LINE;
	tableContent += NEW_LINE;

	delete resultRepresentation1;
	delete resultRepresentation2;
}

void TexWriter::write(string filename){
	ofstream writerStream;
	writerStream.open(filename.c_str());


	string packages = generateIncludedPackages();


	writerStream << LATEX_DOCUMENT_CLASS;
	writerStream << packages;
	writerStream << LATEX_BEGIN_DOCUMENT;
	writerStream << LATEX_BEGIN_TABLE;
	writerStream << tableHeader;
	writerStream << tableContent;
	writerStream << LATEX_END_TABLE;
	writerStream << LATEX_END_DOCUMENT;

	writerStream.flush();
	writerStream.close();
}


string TexWriter::generateIncludedPackages(){

	string packages = ""; 
	packages += LATEX_USE_PACKAGE_FONT;
	packages += NEW_LINE;
	packages += LATEX_USE_PACKAGE_ENCODING;
	packages += NEW_LINE;
	packages += LATEX_USE_PACKAGE_BABEL;
	packages += NEW_LINE;
	packages += LATEX_USE_PACKAGE_MULTIROW;
	packages += NEW_LINE;
	packages += LATEX_USE_PACKAGE_LONGTABLE;
	packages += NEW_LINE;
	packages += LATEX_USE_PACKAGE_COLOR;
	packages += NEW_LINE;

	return packages;

}


TexResultRepresentation::TexResultRepresentation(TestResult *result){

	if(result == NULL){
		time = RESULT_FAILED;
		edgesCount = RESULT_FAILED;
		return;
	}

	__int64 timeAsNum = result -> getExecutionTime();
	__int64 edgesAsNum = result -> getEdgesCount();

	if(timeAsNum == -1){
		time = RESULT_NO_TIME;
	}else {
		time = numberToString(timeAsNum);
	}

	if(edgesAsNum == -1){
		edgesCount = RESULT_NO_EDGES;
	}else{
		edgesCount = numberToString(edgesAsNum);
	}

}

TexResultRepresentation::~TexResultRepresentation(){
}
string TexResultRepresentation::getTime(){
	return time;
}

string TexResultRepresentation::getEdgesCount(){
	return edgesCount;
}


string latexString(string input){
	if(!latexReservedCharsetInitialized){
		initializeLatexReservedSymbolMap();
		latexReservedCharsetInitialized = true;
	}

	string output = "";
	for(string::iterator i = input.begin(); i < input.end(); i++){
		char c = *i;
		if(LATEX_RESERVED_CHARS.find(c) == LATEX_RESERVED_CHARS.end()){
			output.append(1, c);
		}else{
			string replacement = LATEX_RESERVED_CHARS.find(c)->second;
			output.append(replacement);
		}
	}
	return output;
}


void initializeLatexReservedSymbolMap(){
	LATEX_RESERVED_CHARS.clear();
	LATEX_RESERVED_CHARS[SYMBOL_NUMBER] = LATEX_SYMBOL_NUMBER;
	LATEX_RESERVED_CHARS[SYMBOL_DOLLAR] = LATEX_SYMBOL_DOLLAR;
	LATEX_RESERVED_CHARS[SYMBOL_PERCENT] = LATEX_SYMBOL_PERCENT;
	LATEX_RESERVED_CHARS[SYMBOL_AMPERSAND] = LATEX_SYMBOL_AMPERSAND;
	LATEX_RESERVED_CHARS[SYMBOL_CARET_CIRCUMFLEX] = LATEX_SYMBOL_CARET_CIRCUMFLEX;
	LATEX_RESERVED_CHARS[SYMBOL_TILDE] = LATEX_SYMBOL_TILDE;
	LATEX_RESERVED_CHARS[SYMBOL_UNDERSCORE] = LATEX_SYMBOL_UNDERSCORE;
	LATEX_RESERVED_CHARS[SYMBOL_OPENING_BRACE] = LATEX_SYMBOL_OPENING_BRACE;
	LATEX_RESERVED_CHARS[SYMBOL_CLOSING_BRACE] = LATEX_SYMBOL_CLOSING_BRACE;
	LATEX_RESERVED_CHARS[*SLASH.c_str()] = LATEX_SYMBOL_BACKSLASH;
	LATEX_RESERVED_CHARS[SYMBOL_GREATHER] = LATEX_SYMBOL_GREATHER;
	LATEX_RESERVED_CHARS[SYMBOL_LESS] = LATEX_SYMBOL_LESS;
}